package transcoder;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.zip.GZIPOutputStream;

/**
 * 最基本的序列化操作
 * User: zhangyong
 * Date: 13-7-28
 * Time: 下午12:01
 * To change this template use File | Settings | File Templates.
 */
public class BaseTranscoder {

    private static Logger logger = LoggerFactory.getLogger(BaseTranscoder.class);

    // values for cache flags
    public static final int MARKER_BYTE = 1;                            //1个字节
    public static final int MARKER_BOOLEAN = 8192;                     //
    public static final int MARKER_INTEGER = 4;                        //4个字节
    public static final int MARKER_LONG = 16384;                       //8个字节
    public static final int MARKER_CHARACTER = 16;                    //2个字节
    public static final int MARKER_STRING = 32;
    public static final int MARKER_STRINGBUFFER = 64;
    public static final int MARKER_FLOAT = 128;
    public static final int MARKER_SHORT = 256;
    public static final int MARKER_DOUBLE = 512;
    public static final int MARKER_DATE = 1024;
    public static final int MARKER_STRINGBUILDER = 2048;
    public static final int MARKER_BYTEARR = 4096;
    public static final int F_COMPRESSED = 2;
    public static final int F_SERIALIZED = 8;

    // default compression threshold
    private static final int COMPRESS_THRESH = 30720;

    private static boolean compressEnable = true;

    private static boolean primitiveAsString = false;

    public static boolean isPrimitive(Object value) {
        return (
                value instanceof Byte ||
                        value instanceof Boolean ||
                        value instanceof Integer ||
                        value instanceof Long ||
                        value instanceof Character ||
                        value instanceof String ||
                        value instanceof StringBuffer ||
                        value instanceof Float ||
                        value instanceof Short ||
                        value instanceof Double ||
                        value instanceof Date ||
                        value instanceof StringBuilder ||
                        value instanceof byte[]
        )
                ? true
                : false;
    }

    public static Integer getMarkedFlag(Object value) {
        if (value instanceof Byte) {
            return MARKER_BYTE;
        }

        if (value instanceof Boolean) {
            return MARKER_BOOLEAN;
        }

        if (value instanceof Integer) {
            return MARKER_INTEGER;
        }

        if (value instanceof Long) {
            return MARKER_LONG;
        }

        if (value instanceof Character) {
            return MARKER_CHARACTER;
        }

        if (value instanceof String) {
            return MARKER_STRING;
        }

        if (value instanceof StringBuffer) {
            return MARKER_STRINGBUFFER;
        }

        if (value instanceof Float) {
            return MARKER_FLOAT;
        }

        if (value instanceof Short) {
            return MARKER_SHORT;
        }

        if (value instanceof Double) {
            return MARKER_DOUBLE;
        }

        if (value instanceof Date) {
            return MARKER_DATE;
        }

        if (value instanceof StringBuilder) {
            return MARKER_STRINGBUILDER;
        }

        if (value instanceof byte[]) {
            return MARKER_BYTEARR;
        }

        return -1;
    }

    /**
     * Encodes supported  primitive types
     * 编码原始的类型
     *
     * @param value Object to encode.
     * @return byte array
     * @throws Exception If fail to encode.
     */
    public static byte[] encodePrimitiveTypes(Object value) throws Exception {
        if (value instanceof Byte) {
            return encode((Byte) value);
        }
        if (value instanceof Boolean) {
            return encode((Boolean) value);
        }
        if (value instanceof Integer) {
            return encode(((Integer) value).intValue());
        }
        if (value instanceof Long) {
            return encode(((Long) value).longValue());
        }
        if (value instanceof Character) {
            return encode((Character) value);
        }
        if (value instanceof String) {
            return encode((String) value);
        }
        if (value instanceof StringBuffer) {
            return encode(value.toString());
        }
        if (value instanceof Short) {
            return encode((Short) value);
        }
        if (value instanceof Double) {
            return encode(((Double) value).doubleValue());
        }
        if (value instanceof Date) {
            return encode((Date) value);
        }
        if (value instanceof StringBuilder) {
            return encode((StringBuilder) value);
        }
        if (value instanceof byte[]) {
            return encode((byte[]) value);
        }
        if (value instanceof Float) {
            return encode(((Float) value).floatValue());
        }
        return null;
    }

    public static byte[] encode(Byte value) {
        byte[] b = new byte[1];
        b[0] = value.byteValue();
        return b;
    }

    /**
     * 布尔实际上是 1 0 用来判断 *
     */
    public static byte[] encode(Boolean value) {
        byte[] b = new byte[1];
        if (value.booleanValue()) {
            b[0] = 1;
        } else {
            b[0] = 0;
        }
        return b;
    }

    /**
     * 重新encode 整形
     * 00000000 00000000 00000000 00000001
     * <p/>
     * 参看博客文章
     * http://makemyownlife.iteye.com/admin/blogs/1047717
     * 也就是 big endian 排序方式
     */
    public static byte[] encode(int value) {
        byte[] b = new byte[4];
        b[0] = (byte) ((value >> 24) & 0xff);       //高位放在第0个字节
        b[1] = (byte) ((value >> 16) & 0xff);
        b[2] = (byte) ((value >> 8) & 0xff);
        b[3] = (byte) ((value >> 0) & 0xFF);
        return b;
    }

    /**
     * 基本的long的用法
     */
    public static byte[] encode(long value) {
        byte[] b = new byte[8];
        b[0] = (byte) ((value >> 56) & 0xFF);
        b[1] = (byte) ((value >> 48) & 0xFF);
        b[2] = (byte) ((value >> 40) & 0xFF);
        b[3] = (byte) ((value >> 32) & 0xFF);
        b[4] = (byte) ((value >> 24) & 0xFF);
        b[5] = (byte) ((value >> 16) & 0xFF);
        b[6] = (byte) ((value >> 8) & 0xFF);
        b[7] = (byte) ((value >> 0) & 0xFF);
        return b;
    }

    /**
     * encode相关代码 *
     */
    public static byte[] encode(Character value) {
        return encode((int) value.charValue());
    }

    public static byte[] encode(String value) throws Exception {
        return value.getBytes("UTF-8");
    }

    public static byte[] encode(StringBuffer value) throws Exception {
        return encode(value.toString());
    }

    public static byte[] encode(Short value) throws Exception {
        return encode((int) value.shortValue());
    }

    public static byte[] encode(double value) throws Exception {
        return encode((long) Double.doubleToLongBits(value));
    }

    public static byte[] encode(Date value) throws Exception {
        return encode(value.getTime());
    }

    public static byte[] encode(StringBuilder value) throws Exception {
        return encode(value.toString());
    }

    public static byte[] encode(byte[] value) {
        return value;
    }

    public static CachedData encode(Object value) throws Exception {
        byte[] val;
        //store flags
        int flags = 0;
        if (isPrimitive(value)) {                                                         //若是原始类型 则直接调用本地方法进行转换
            if (primitiveAsString) {
                try {
                    val = value.toString().getBytes("UTF-8");
                } catch (UnsupportedEncodingException e) {
                    throw new UnsupportedEncodingException();
                }
            } else {
                logger.info("Storing with native handler...");
                //按位或运算符“|”，任何一个运算数为1，则结果为1。如下面的例子所示：  00101010 42 | 00001111 15  00101111 47
                flags |= getMarkedFlag(value);
                val = encodePrimitiveTypes(value);
            }
        } else {                                                                       //非原始类型           t
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            (new ObjectOutputStream(bos)).writeObject(value);
            val = bos.toByteArray();
            flags |= F_SERIALIZED;
        }
        //尝试压缩 如果字节大于多少则尝试压缩
        if (compressEnable && val.length > COMPRESS_THRESH) {
            logger.info("++++ trying to compress data");
            logger.info("++++ size prior to compression: " + val.length);
            ByteArrayOutputStream bos = new ByteArrayOutputStream(val.length);
            GZIPOutputStream gos = new GZIPOutputStream(bos);
            gos.write(val, 0, val.length);
            gos.finish();
            gos.close();

            val = bos.toByteArray();
            flags |= F_COMPRESSED;
        }

        CachedData cachedData = new CachedData();
        cachedData.setData(val);
        cachedData.setFlag(flags);
        return cachedData;
    }

    public static void main(String[] args) {
        byte b = (byte) 1;
        System.out.println(b >> 24);
        int x = 0x11000000;
        System.out.println(x);
        System.out.println(x & 0xFF);
        System.out.println((x >> 24) & 0xFF);

        int m = 0xFFFFFFE8;
        System.out.println(m);

        System.out.println(Float.MAX_VALUE);
    }

}
